// ============================================================================
// Name : PackageNamesScanner.java
// Author : iron.yin@gmail.com
// Version : v1.0
// Copyright : RisingSun CO,.LTD
// Description : PackageNamesScanner.java in Java
// ============================================================================
package cc.risingsun.wing.core.scanner;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cc.risingsun.wing.core.reflect.ReflectionHelper;
import cc.risingsun.wing.ds.DataStruct;

/**
 * 
 * @author iron.yin@gmail.com
 */
public class PackageNamesScanner implements Scanner {

	private final static Logger logger = LoggerFactory.getLogger("PackageNamesScanner");
	private final String[] packages;
	private final ClassLoader classLoader;
	private final Map<String, UriSchemeScanner> scanners;

	public PackageNamesScanner(String... packages) {
		this(ReflectionHelper.getContextClassLoader(), packages);
	}

	public PackageNamesScanner(ClassLoader classLoader, String... packages) {
		this.classLoader = classLoader;
		this.packages = packages;
		this.scanners = DataStruct.hashMap();

		initScanner();
	}

	private void initScanner() {
		add(new FileSchemeScanner());
	}

	private void add(final UriSchemeScanner scanner) {
		for (final String s : scanner.getSchemes()) {
			scanners.put(s.toLowerCase(), scanner);
		}
	}

	@Override
	public void scan(final ScannerListener listener) {
		for (final String p : packages) {
			try {
				final Enumeration<URL> urls = classLoader.getResources(p.replace('.', '/'));
				while (urls.hasMoreElements()) {
					final URI uri = toURI(urls.nextElement());
					if (uri == null)
						continue;
					scan(uri, listener);
				}
			} catch (IOException e) {
				logger.error(e.getMessage(), e);
			}
		}
	}

	private void scan(final URI uri, final ScannerListener listener) {
		final UriSchemeScanner scanner = scanners.get(uri.getScheme().toLowerCase());
		if (scanner != null)
			scanner.scan(uri, listener);
		else
			throw new ScannerException("The URI scheme " + uri.getScheme()
					+ " of the URI " + uri
					+ " is not supported. Package scanning deployment is not");
	}

	private URI toURI(URL url) {
		try {
			return url.toURI();
		} catch (URISyntaxException e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}
}
